package guestbook;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import sun.misc.IOUtils;

public class SignGuestbookServlet extends HttpServlet {
    public void doPost(HttpServletRequest req, HttpServletResponse resp)
                throws IOException {
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();
        boolean Is_Randome = false;
        
        // We have one entity group per Guestbook with all Greetings residing
        // in the same entity group as the Guestbook to which they belong.
        // This lets us run a transactional ancestor query to retrieve all
        // Greetings for a given Guestbook.  However, the write rate to each
        // Guestbook should be limited to ~1/second.
      //  long tStart = System.currentTimeMillis();
        
        String guestbookName = req.getParameter("guestbookName");
        Key guestbookKey = KeyFactory.createKey("Guestbook", guestbookName);
        String content = req.getParameter("content");
       
        int length = req.getContentLength();
        DecimalFormat df = new DecimalFormat("#.###");
      
        System.err.println("Request sue " + length );
        // Contents must be form like ID;Tasks
        String TaskID="";
        String Amount_of_Task;
        String Returning_Result = null;
        double y = 0.0;
        Entity greeting = new Entity("Greeting", guestbookKey);
        String [] RequestedTasks;
        
        System.out.println(content);

        Random random = new Random(); 
        RequestedTasks = content.split(":");
        if(Is_Randome = true){
            for(int i = 0 ; i < RequestedTasks.length ; i++){
            	String [] IDandTask = RequestedTasks[i].split(";");
            	TaskID = IDandTask[0];
            	Amount_of_Task = IDandTask[1];
              	int counter = Integer.parseInt(Amount_of_Task);
              	
              	for(int ii = 1 ; ii <= counter; ii ++ )
              	{
              	       double z  =  random.nextInt(800)+1;
              	       double mu    =  random.nextInt(500)+1;
              	       double sigma =   random.nextInt(900)+1;
              	   //  Result += Phi(z, mu, sigma)+":";
              	       Phi(z, mu, sigma);
               	      //  y += Phi(Math.tan(Math.tan(Math.tan(z))), Math.tan(Math.tan(mu)), Math.tan(Math.tan(sigma)));
               	     y += Phi(Math.tan(Math.tan(Math.tan(z))), Math.tan(Math.tan(mu)), Math.tan(Math.tan(sigma)))/ PhiInverse(Math.tan( Math.tan( Math.tan( Math.tan(PhiInverse(y))))));
               	       PhiInverse(y);
              	}
              //	System.out.println("Total Phi " +  y + " Counter "  + counter );
              	y /= counter;
              	
              	 if(Returning_Result==null){
              		
                 	Returning_Result = TaskID +";"+ df.format(y);
                 }
                 else{
                	df.format(y);
                 	Returning_Result = Returning_Result+":" + TaskID +";"+ df.format(y);
                 }
            }
                
            System.out.println("System Result " + Returning_Result);
        }
        else{
        	
        }


          resp.setContentType("text/html");
  		PrintWriter out = resp.getWriter();
  		out.println("Headers<hr/>");
  		Enumeration<String> headerNames = req.getHeaderNames();

  		while (headerNames.hasMoreElements()) {
  			String headerName = headerNames.nextElement();
  			
  			out.print("Header Name: <em>" + headerName);
  			String headerValue = req.getHeader(headerName);
  			out.print("</em>, Header Value: <em>" + headerValue);
  			out.println("</em><br/>");
  		}

  		out.println("<hr/>");

  		out.println("request content-length: " + req.getHeader("content-length"));

        String ResultsGus = Returning_Result;//"result;" + TaskID +";" +elapsedSeconds + " ";// +"res " + String.valueOf(len) ;
        System.err.println(ResultsGus);
        

        
        PrintWriter out1 = resp.getWriter();
        out1.println("Hello: " + ResultsGus);
        
              out.flush();
              out1.flush();
    }
    
    
    public static double phi(double x) {
        return Math.exp(-x*x / 2) / Math.sqrt(2 * Math.PI);
    }

    // return phi(x, mu, signma) = Gaussian pdf with mean mu and stddev sigma
    public static double phi(double x, double mu, double sigma) {
        return phi((x - mu) / sigma) / sigma;
    }

    // return Phi(z) = standard Gaussian cdf using Taylor approximation
    public static double Phi(double z) {
        if (z < -8.0) return 0.0;
        if (z >  8.0) return 1.0;
        double sum = 0.0, term = z;
        for (int i = 3; sum + term != sum; i += 2) {
            sum  = sum + term;
            term = term * z * z / i;
        }
        return 0.5 + sum * phi(z);
    }

    // return Phi(z, mu, sigma) = Gaussian cdf with mean mu and stddev sigma
    public static double Phi(double z, double mu, double sigma) {
        return Phi((z - mu) / sigma);
    } 

    // Compute z such that Phi(z) = y via bisection search
    public static double PhiInverse(double y) {
        return PhiInverse(y, .00000001, -8, 8);
    } 

    // bisection search
    private static double PhiInverse(double y, double delta, double lo, double hi) {
        double mid = lo + (hi - lo) / 2;
        if (hi - lo < delta) return mid;
        if (Phi(mid) > y) return PhiInverse(y, delta, lo, mid);
        else              return PhiInverse(y, delta, mid, hi);
    }
}